001package ball.databind.ant.taskdefs; 002/*- 003 * ########################################################################## 004 * Data Binding Utilities 005 * $Id: ObjectMapperTask.java 5285 2020-02-05 04:23:21Z ball $ 006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/ball-databind/trunk/src/main/java/ball/databind/ant/taskdefs/ObjectMapperTask.java $ 007 * %% 008 * Copyright (C) 2016 - 2020 Allen D. Ball 009 * %% 010 * Licensed under the Apache License, Version 2.0 (the "License"); 011 * you may not use this file except in compliance with the License. 012 * You may obtain a copy of the License at 013 * 014 * http://www.apache.org/licenses/LICENSE-2.0 015 * 016 * Unless required by applicable law or agreed to in writing, software 017 * distributed under the License is distributed on an "AS IS" BASIS, 018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 019 * See the License for the specific language governing permissions and 020 * limitations under the License. 021 * ########################################################################## 022 */ 023import ball.databind.ObjectMapperFeature; 024import ball.util.ant.taskdefs.AnnotatedAntTask; 025import ball.util.ant.taskdefs.AntTask; 026import ball.util.ant.taskdefs.ClasspathDelegateAntTask; 027import ball.util.ant.taskdefs.ConfigurableAntTask; 028import ball.util.ant.taskdefs.NotNull; 029import ball.util.ant.types.StringAttributeType; 030import com.fasterxml.jackson.databind.JavaType; 031import com.fasterxml.jackson.databind.ObjectMapper; 032import com.fasterxml.jackson.databind.type.TypeFactory; 033import java.io.File; 034import java.util.ArrayList; 035import java.util.Arrays; 036import java.util.Collection; 037import java.util.Map; 038import java.util.SortedMap; 039import java.util.TreeMap; 040import lombok.Getter; 041import lombok.NoArgsConstructor; 042import lombok.Setter; 043import lombok.ToString; 044import lombok.experimental.Accessors; 045import org.apache.tools.ant.BuildException; 046import org.apache.tools.ant.PropertyHelper; 047import org.apache.tools.ant.Task; 048import org.apache.tools.ant.util.ClasspathUtils; 049 050import static ball.databind.ObjectMapperFeature.MAP; 051import static java.util.Objects.requireNonNull; 052import static org.apache.commons.lang3.StringUtils.isEmpty; 053 054/** 055 * Abstract {@link.uri http://ant.apache.org/ Ant} base {@link Task} for 056 * {@link ObjectMapper} tasks. 057 * 058 * {@ant.task} 059 * 060 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 061 * @version $Revision: 5285 $ 062 */ 063public abstract class ObjectMapperTask extends Task 064 implements AnnotatedAntTask, 065 ClasspathDelegateAntTask, 066 ConfigurableAntTask { 067 @Getter @Setter @Accessors(chain = true, fluent = true) 068 private ClasspathUtils.Delegate delegate = null; 069 @Getter @Setter 070 private boolean registerModules = false; 071 private final ArrayList<Setting> settings = new ArrayList<>(); 072 protected final ObjectMapper mapper; 073 074 /** 075 * No-argument constructor. 076 */ 077 protected ObjectMapperTask() { this(new ObjectMapper()); } 078 079 /** 080 * Protected constructor to allow subclasses to specify the 081 * {@link ObjectMapper}. 082 * 083 * @param mapper The {@link ObjectMapper}. 084 */ 085 protected ObjectMapperTask(ObjectMapper mapper) { 086 super(); 087 088 this.mapper = requireNonNull(mapper, "mapper"); 089 } 090 091 public void addConfiguredConfigure(Setting setting) { 092 settings.add(setting); 093 } 094 095 @Override 096 public void init() throws BuildException { 097 super.init(); 098 ClasspathDelegateAntTask.super.init(); 099 ConfigurableAntTask.super.init(); 100 101 try { 102 if (isRegisterModules()) { 103 mapper.registerModules(ObjectMapper.findModules(getClassLoader())); 104 } 105 106 for (Map.Entry<String,Object> entry : 107 getProject().getProperties().entrySet()) { 108 if (MAP.containsKey(entry.getKey())) { 109 ObjectMapperFeature.configure(mapper, 110 MAP.get(entry.getKey()), 111 PropertyHelper.toBoolean(entry.getValue())); 112 } 113 } 114 115 for (Setting setting : settings) { 116 ObjectMapperFeature.configure(mapper, 117 setting.getEnum(), 118 setting.booleanValue()); 119 } 120 } catch (BuildException exception) { 121 throw exception; 122 } catch (Throwable throwable) { 123 throw new BuildException(throwable); 124 } 125 } 126 127 @Override 128 public void execute() throws BuildException { 129 super.execute(); 130 AnnotatedAntTask.super.execute(); 131 } 132 133 /** 134 * {@link ObjectMapper} configuration setting. 135 * 136 * {@bean.info} 137 */ 138 @NoArgsConstructor @ToString 139 public static class Setting extends StringAttributeType { 140 141 /** 142 * Method to get the feature {@link Enum}. 143 * 144 * @return The feature {@link Enum}. 145 */ 146 public Enum<?> getEnum() { return MAP.get(getName()); } 147 148 /** 149 * Method to get the feature boolean value. 150 * 151 * @return The feature boolean value. 152 */ 153 public boolean booleanValue() { 154 return (isEmpty(getValue()) 155 ? true 156 : PropertyHelper.toBoolean(getValue())); 157 } 158 } 159 160 /** 161 * {@link.uri http://ant.apache.org/ Ant} 162 * {@link org.apache.tools.ant.Task} to invoke 163 * {@link ObjectMapper#readValue(File,Class)}. 164 * 165 * {@ant.task} 166 */ 167 @AntTask("om-read-value") 168 @ToString 169 public static class ReadValue extends ObjectMapperTask { 170 @NotNull @Getter @Setter 171 private File file = null; 172 @NotNull @Getter @Setter 173 private String type = null; 174 @Getter @Setter 175 private String collection = null; 176 177 /** 178 * No-argument constructor. 179 */ 180 public ReadValue() { this(new ObjectMapper()); } 181 182 /** 183 * Protected constructor to allow subclasses to specify the 184 * {@link ObjectMapper}. 185 * 186 * @param mapper The {@link ObjectMapper}. 187 */ 188 protected ReadValue(ObjectMapper mapper) { super(mapper); } 189 190 /** 191 * Method to construct a {@link JavaType} from {@code getType()} and 192 * {@code getCollection()}. 193 * 194 * @return The {@link JavaType}. 195 * 196 * @throws Exception If the {@link JavaType} cannot be 197 * constructed. 198 */ 199 protected JavaType getJavaType() throws Exception { 200 TypeFactory factory = mapper.getTypeFactory(); 201 JavaType type = null; 202 203 if (! isEmpty(getCollection())) { 204 type = 205 factory 206 .constructCollectionType(getClassForName(getCollection()) 207 .asSubclass(Collection.class), 208 getClassForName(getType())); 209 } else { 210 type = 211 factory 212 .constructSimpleType(getClassForName(getType()), 213 new JavaType[] { }); 214 } 215 216 return type; 217 } 218 219 @Override 220 public void execute() throws BuildException { 221 super.execute(); 222 223 try { 224 Object value = mapper.readValue(getFile(), getJavaType()); 225 226 log(String.valueOf(value)); 227 } catch (BuildException exception) { 228 throw exception; 229 } catch (Throwable throwable) { 230 throw new BuildException(throwable); 231 } 232 } 233 } 234}