dynamic values in tags object of swagger - spring-boot

I want to provide values from properties file in tags section of the swagger for ex: tags = "${metric.tags}" but not able to pickup from properties file. for values it is working fine value = "${metric.value}".

I have made plugin configuration in swagger configuration file and it started working as per my requirement.
#Bean
public TranslationOperationBuilderPlugin translationPlugin() {
return new TranslationOperationBuilderPlugin();
}
#Order(Ordered.LOWEST_PRECEDENCE)
public static class TranslationOperationBuilderPlugin implements OperationBuilderPlugin {
#Autowired
Environment environment;
#Override
public boolean supports(DocumentationType delimiter) {
return true;
}
#Override
public void apply(OperationContext context) {
String summary = context.operationBuilder().build().getSummary();
String notes = context.operationBuilder().build().getNotes();
Set<String>tags = context.operationBuilder().build().getTags();
Set<String>translatedTags= new HashSet<>();
for(String tag:tags) {
if(environment.getProperty(tag)!=null) {
translatedTags.add(environment.getProperty(tag));
}else {
translatedTags.add(tag);
}
}
ModelReference modelReference= context.operationBuilder().build().getResponseModel();
AllowableListValues allowableValues=(AllowableListValues) modelReference.getAllowableValues();
if(allowableValues!=null && allowableValues.getValues()!=null) {
List<String> translatedAllowables=new ArrayList<>();
for(String value:allowableValues.getValues()) {
if(environment.getProperty(value)!=null) {
translatedAllowables.add(environment.getProperty(value));
}else {
translatedAllowables.add(value);
}
}
allowableValues.getValues().removeAll(allowableValues.getValues());
allowableValues.getValues().addAll(translatedAllowables);
}
//String summaryTranslated = apiDescriptionPropertiesReader.getProperty(summary);
//String notesTranslated = apiDescriptionPropertiesReader.getProperty(notes);
//context.operationBuilder().summary(summaryTranslated);
//context.operationBuilder().notes(notesTranslated);
context.operationBuilder().tags(translatedTags);
}

Related

Using Baggage in OpenTelemetry Spring application

I have a spring boot application where i have instrumented my code using automatic instrumentation.
Now in my application i am trying to attach a baggage in the traces or some specific span.
I know it uses contextPropagation. but i am not able to implement how contextPropagator, baggage and span work together.
Here is my relevant code implementation:
#WithSpan
private void doSomeWorkNewSpan() {
logger.info("Doing some work In New span");
Span span = Span.current();
ContextPropagators contextPropagators = new ContextPropagators() {
#Override
public TextMapPropagator getTextMapPropagator() {
return null;
}
};
Context context = new Context() {
#Override
public <V> V get(ContextKey<V> contextKey) {
return null;
}
#Override
public <V> Context with(ContextKey<V> contextKey, V v) {
return null;
}
};
Baggage baggage = new Baggage() {
#Override
public int size() {
return 0;
}
#Override
public void forEach(BiConsumer<? super String, ? super BaggageEntry> biConsumer) {
}
#Override
public Map<String, BaggageEntry> asMap() {
return null;
}
#Override
public String getEntryValue(String s) {
return null;
}
#Override
public BaggageBuilder toBuilder() {
return null;
}
};
baggage.storeInContext(context);
// span.storeInContext();
span.setAttribute("crun","yes");
span.addEvent("app.processing2.start", atttributes("321"));
span.addEvent("app.processing2.end", atttributes("321"));
}
private Attributes atttributes(String id) {
return Attributes.of(AttributeKey.stringKey("app.id"), id);
}

How to make Hibernate use setFixedCHAR instead of setString

Can I somehow modify the way Hibernate binds parameters to the query?
For example, I want hibernate to use OracleResultSet.setFixedChar() when executing on an string column, instead of rs.setString() when executing a JPA query via Spring data.
This is how I would do it without Hibernate:
try(PreparedStatement ps = con.executeQuery("...")) {
if(ps.isWrapped(OraclePreparedStatement.class) {
ps.unwrap(OraclePreparedStatement.class).setFixedCHAR(0, myStringField);
} else {
ps.setString(0, myStringField);
}
try(ResultSet rs = ps.getResultSet()) {
while(rs.next()) {
... do stuff ...
}
}
}
Repository method (Spring data JPA):
List<Object> findByMyStringField(String myStringField);
How can I influence how Hibernate binds my variable. With the above example setString is used always.
As background: the problem is that all our Legacy DB's use CHAR columns and not VARCHAR2, so we have to deal with whitespace and setFixedCHAR should do exactly what we would want.
Found a solution by implementing a SqlTypeDescriptor & Custom Dialect:
#Autowired
private DataSource source;
#Bean
public HibernateJpaVendorAdapter getHibernateJPAVendorAdapter() {
return new CustomHibernateJpaVendorAdaptor();
}
private static class CustomHibernateJpaVendorAdaptor extends HibernateJpaVendorAdapter {
#Override
protected Class<?> determineDatabaseDialectClass(Database database) {
// if HSQL is copied from Spring Sourcecode to keep everything the same
if (Database.HSQL.equals(database)) {
return CustomHsqlDialect.class;
}
try {
if (source.isWrapperFor(OracleDataSource.class)) {
return CustomOracleDialect.class;
}
} catch (SQLException e) {
}
return super.determineDatabaseDialectClass(database);
}
private class CustomHsqlDialect extends HSQLDialect {
public CustomHsqlDialect() {
registerColumnType(Types.BOOLEAN, "boolean");
registerHibernateType(Types.BOOLEAN, "boolean");
}
}
}
#NoArgsConstructor
public static class CustomOracleDialect extends Oracle12cDialect {
private static final OracleCharFix INSTANCE = new OracleCharFix();
#Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(final int sqlCode) {
switch (sqlCode) {
case Types.VARCHAR:
return INSTANCE;
default:
return super.getSqlTypeDescriptorOverride(sqlCode);
}
}
}
#Slf4j
private static class OracleCharFix extends CharTypeDescriptor {
#Override
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<>(javaTypeDescriptor, this) {
#Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
throws SQLException {
if (st.isWrapperFor(OraclePreparedStatement.class)) {
OraclePreparedStatement ops = st.unwrap(OraclePreparedStatement.class);
if (ops.getParameterMetaData().getParameterType(index) == Types.CHAR) {
ops.setFixedCHAR(index, javaTypeDescriptor.unwrap(value, String.class, options));
} else {
st.setString(index, javaTypeDescriptor.unwrap(value, String.class, options));
}
} else {
st.setString(index, javaTypeDescriptor.unwrap(value, String.class, options));
}
}
#Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
//Is nolonger used by Hibernate in the current Version
st.setString(name, javaTypeDescriptor.unwrap(value, String.class, options));
}
private boolean checkIfCHARByName(ResultSetMetaData metadata, String name)
throws SQLException {
for (int i = 1; i <= metadata.getColumnCount(); i++) {
if (metadata.getColumnType(i) == Types.CHAR && Objects.equals(metadata.getColumnName(i), name)) {
return true;
}
}
return false;
}
};
}

How to implement custom SftpSimplePatternFileListFilter?

I am newbee to Spring integration. i am trying to implement customer sftp filter to list the files in SFTP server. I am getting "The blank final field seen may not have been initialized" at the constructor.Can you please suggest me to get list of file names from sftp server.
I dont have any idea what went wrong in my code.
Thanks in Advance
java code
public class SFTPFileFilter extends SftpSimplePatternFileListFilter {
public SFTPFileFilter(String pattern) {
super(pattern);
// TODO Auto-generated constructor stub
}
final static Logger logger = LoggerFactory.getLogger(SFTPFileFilter.class);
private final Queue<File> seen;
private final Set<File> seenSet = new HashSet<File>();
private final Object monitor = new Object();
public static int fileCount = 0;
#Autowired
private SourcePollingChannelAdapter sftpInbondAdapter;
public List<File> filterFiles(File[] files)
{
List<File> accepted = new ArrayList<File>();
for (File file : files) {
System.out.println(file.getName());
accepted.add(file);
}
return accepted;
}
public boolean accept(File file) {
synchronized (this.monitor) {
if (this.seenSet.contains(file)) {
logger.info(file.getName()+" is already copied earlier");
return false;
}
if (this.seen != null) {
if (!this.seen.offer(file)) {
File removed = this.seen.poll();
this.seenSet.remove(removed);
this.seen.add(file);
}
}
this.seenSet.add(file);
return true;
}
}
}
private final Queue<File> seen;
You are not initializing that field in a constructor.
You can't extend it like that; simply override the method like this...
public List<File> filterFiles(File[] files) {
for (File file : files) {
System.out.println("received:" + file.getName());
}
List<File> filtered = super.filterFiles(files);
for (File file : flteredFiles) {
System.out.println("after filter:" + file.getName());
}
return filteredFiles;
}

Using multiple res folders with Robolectric

My current Gradle configuration has multiple (Merged) res folders:
sourceSets {
androidTest {
setRoot('src/test')
}
main {
res.srcDirs =
[
'src/main/res/features/registration',
'src/main/res/features/login',
'src/main/res'
]
}
}
But Robolectric allows me to configure a single directory using AndroidManifest:
public class RobolectricGradleTestRunner extends RobolectricTestRunner {
private static final int MAX_SDK_SUPPORTED_BY_ROBOLECTRIC = 18;
public RobolectricGradleTestRunner(Class<?> testClass) throws InitializationError {
super(testClass);
}
#Override
protected AndroidManifest getAppManifest(Config config) {
String manifestProperty = "../app/src/main/AndroidManifest.xml";
String resProperty = "../app/src/main/res";
return new AndroidManifest(Fs.fileFromPath(manifestProperty), Fs.fileFromPath(resProperty)) {
#Override
public int getTargetSdkVersion() {
return MAX_SDK_SUPPORTED_BY_ROBOLECTRIC;
}
};
}
}
This way tests are failing. Is it possible to configure robolectric to reflect my gradle file?
Another solution similar to Luca's:
public class MyTestRunner extends RobolectricTestRunner {
...
#Override
protected AndroidManifest getAppManifest(Config config) {
String appRoot = "./src/main/";
String manifestPath = appRoot + "AndroidManifest.xml";
String resDir = appRoot + "res";
String assetsDir = appRoot + "assets";
return new AndroidManifest(Fs.fileFromPath(manifestPath), Fs.fileFromPath(resDir), Fs.fileFromPath(assetsDir)) {
#Override
public List<ResourcePath> getIncludedResourcePaths() {
List<ResourcePath> paths = super.getIncludedResourcePaths();
paths.add(new ResourcePath(getRClass(), getPackageName(), Fs.fileFromPath("../app/src/main/res/features/registration"), getAssetsDirectory()));
paths.add(new ResourcePath(getRClass(), getPackageName(), Fs.fileFromPath("../app/src/main/res/features/login"), getAssetsDirectory()));
return paths;
}
};
}
}
Don't forget to annotate your tests with #RunWith(MyTestRunner.class)
Ok, this is the easiest way to do it, You will have to extend RobolectricTestRunner getAppManifest and createAppResourceLoader.
In getAppManifest you will simply have to store the manifest in a field, let's say mDefaultManifest.
In createAppResourceLoader you will have to add the right resources injected.
/**
* TODO: Watch OUT this is copied from RobolectricTestRunner in Robolectric-2.4 keep it up to date!
*/
#Override
protected ResourceLoader createAppResourceLoader(ResourceLoader systemResourceLoader, AndroidManifest appManifest) {
List<PackageResourceLoader> appAndLibraryResourceLoaders = new ArrayList<PackageResourceLoader>();
for (ResourcePath resourcePath : appManifest.getIncludedResourcePaths()) {
appAndLibraryResourceLoaders.add(createResourceLoader(resourcePath));
}
/* BEGIN EDIT */
if(mDefaultManifest != null) {
ResourcePath rpInjected = new ResourcePath(mDefaultManifest.getRClass(), mDefaultManifest.getPackageName(), Fs.fileFromPath("../app/src/main/res/features/registration"), mDefaultManifest.getAssetsDirectory());
appAndLibraryResourceLoaders.add(createResourceLoader(rpInjected));
rpInjected = new ResourcePath(mDefaultManifest.getRClass(), mDefaultManifest.getPackageName(), Fs.fileFromPath("../app/src/main/res/features/login"), mDefaultManifest.getAssetsDirectory());
appAndLibraryResourceLoaders.add(createResourceLoader(rpInjected));
}
/* END EDIT */
OverlayResourceLoader overlayResourceLoader = new OverlayResourceLoader(appManifest.getPackageName(), appAndLibraryResourceLoaders);
Map<String, ResourceLoader> resourceLoaders = new HashMap<String, ResourceLoader>();
resourceLoaders.put("android", systemResourceLoader);
resourceLoaders.put(appManifest.getPackageName(), overlayResourceLoader);
return new RoutingResourceLoader(resourceLoaders);
}
Do not forget to add #RunWith(YourTestRunner.class) in your test classes.

Initial data on JPA repositories

I'm looking for a convenient way to provide initial data for my application. Currently I've implemented a Spring Data JPA based project which is my foundation of all database related operation.
Example:
I've got a entity Role which can be assigned to the entity User. On a clean application start I would like to provide directly some default roles (e.g. admin, manager, etc).
Best
I built a random data factory :
public class RandomDataFactory {
private static final String UNGENERATED_VALUE_MARKER = "UNGENERATED_VALUE_MARKER";
private static void randomlyPopulateFields(Object object) {
new RandomValueFieldPopulator().populate(object);
}
/**
* Instantiates a single object with random data
*/
public static <T> T getSingle(Class<T> clazz) throws IllegalAccessException, InstantiationException {
T object = clazz.newInstance();
randomlyPopulateFields(object);
return object;
}
/**
* Returns an unmodifiable list of specified type objects with random data
*
* #param clazz the myPojo.class to be instantiated with random data
* #param maxLength the length of list to be returned
*/
public static <T> List<T> getList(Class<T> clazz, int maxLength) throws IllegalAccessException, InstantiationException {
List<T> list = new ArrayList<T>(maxLength);
for (int i = 0; i < maxLength; i++) {
T object = clazz.newInstance();
randomlyPopulateFields(object);
list.add(i, object);
}
return Collections.unmodifiableList(list);
}
/**
* Returns a unmodifiable list of specified type T objects with random data
* <p>List length will be 3</p>
*
* #param clazz the myPojo.class to be instantiated with random data
*/
public static <T> List<T> getList(Class<T> clazz) throws InstantiationException, IllegalAccessException {
return getList(clazz, 3);
}
public static <T> T getPrimitive(Class<T> clazz) {
return (T) RandomValueFieldPopulator.generateRandomValue(clazz);
}
public static <T> List<T> getPrimitiveList(Class<T> clazz) {
return getPrimitiveList(clazz, 3);
}
public static <T> List<T> getPrimitiveList(Class<T> clazz, int length) {
List<T> randoms = new ArrayList<T>(length);
for (int i = 0; i < length; i++) {
randoms.add(getPrimitive(clazz));
}
return randoms;
}
private static class RandomValueFieldPopulator {
public static Object generateRandomValue(Class<?> fieldType) {
Random random = new Random();
if (fieldType.equals(String.class)) {
return UUID.randomUUID().toString();
} else if (Date.class.isAssignableFrom(fieldType)) {
return new Date(System.currentTimeMillis() - random.nextInt());
} else if (LocalDate.class.isAssignableFrom(fieldType)) {
Date date = new Date(System.currentTimeMillis() - random.nextInt());
return new LocalDate(date);
} else if (fieldType.equals(Character.class) || fieldType.equals(Character.TYPE)) {
return (char) (random.nextInt(26) + 'a');
} else if (fieldType.equals(Integer.TYPE) || fieldType.equals(Integer.class)) {
return random.nextInt();
} else if (fieldType.equals(Short.TYPE) || fieldType.equals(Short.class)) {
return (short) random.nextInt();
} else if (fieldType.equals(Long.TYPE) || fieldType.equals(Long.class)) {
return random.nextLong();
} else if (fieldType.equals(Float.TYPE) || fieldType.equals(Float.class)) {
return random.nextFloat();
} else if (fieldType.equals(Double.TYPE)) {
return random.nextInt(); //if double is used, jsonPath uses bigdecimal to convert back
} else if (fieldType.equals(Double.class)) {
return random.nextDouble(); //if double is used, jsonPath uses bigdecimal to convert back
} else if (fieldType.equals(Boolean.TYPE) || fieldType.equals(Boolean.class)) {
return random.nextBoolean();
} else if (fieldType.equals(BigDecimal.class)) {
return new BigDecimal(random.nextFloat());
} else if (Enum.class.isAssignableFrom(fieldType)) {
Object[] enumValues = fieldType.getEnumConstants();
return enumValues[random.nextInt(enumValues.length)];
} else if (Number.class.isAssignableFrom(fieldType)) {
return random.nextInt(Byte.MAX_VALUE) + 1;
} else {
return UNGENERATED_VALUE_MARKER;
}
public void populate(Object object) {
ReflectionUtils.doWithFields(object.getClass(), new RandomValueFieldSetterCallback(object));
}
private static class RandomValueFieldSetterCallback implements ReflectionUtils.FieldCallback {
private final Object targetObject;
public RandomValueFieldSetterCallback(Object targetObject) {
this.targetObject = targetObject;
}
#Override
public void doWith(Field field) throws IllegalAccessException {
Class<?> fieldType = field.getType();
if (!Modifier.isFinal(field.getModifiers())) {
Object value = generateRandomValue(fieldType);
if (!value.equals(UNGENERATED_VALUE_MARKER)) {
ReflectionUtils.makeAccessible(field);
field.set(targetObject, value);
}
}
}
}
}
}
Look into an in-memory H2 database.
http://www.h2database.com/html/main.html
Maven Dependency
<!-- H2 Database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.178</version>
</dependency>
Spring Java Config Entry
#Bean
public DataSource dataSource() {
System.out.println("**** USING H2 DATABASE ****");
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.H2).addScript("/schema.sql").build();
}
You can create/load the H2 database w/ a SQL script in the above code using .addscript().
If you are using it for Unit test, and need a different state for different test, then
There is a http://dbunit.sourceforge.net/
Specifically for Spring there is http://springtestdbunit.github.io/spring-test-dbunit/
If you need to initialize it only once and using EmbeddedDatabaseBuilder for testing, then as Brandon said, you can use EmbeddedDatabaseBuilder.
#Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.H2).addScript("/schema.sql").build();
}
If you want it to be initialised on application start, you can add #PostConstruct function to your Configuration bean, and it will be initialised after configuration bean was created.
#PostConstruct
public void initializeDB() {
}

Resources